package com.support.mvc.entity.base;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.querydsl.core.QueryResults;
import com.utils.ICall;
import com.utils.ICode;
import com.utils.entity.ResponseResult;
import com.utils.enums.Code;
import com.utils.exception.CodeException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 返回结果集对象
 *
 * @author 谢长春 2017-9-20
 */
@ToString(callSuper = true)
@Slf4j
@Accessors(chain = true)
@ApiModel(description = "全局通用响应对象")
@JSONType(orders = {"code", "message", "rowCount", "pageCount", "totalCount", "xid", "exception", "data", "extras"})
public class Result<E> extends ResponseResult<E> {

    /**
     * 默认构造函数
     */
    public Result() {
        super();
    }

    /**
     * 带参构造函数
     *
     * @param code {@link ICode} 操作响应码
     */
    public Result(final ICode code) {
        super(code);
        this.code = code.name();
    }

    @ApiModelProperty(position = 1, value = "状态码")
    private String code;

    @Setter
    @ApiModelProperty(position = 2, value = "响应消息，用于页面弹窗内容")
    private String message;

    @ApiModelProperty(position = 3, value = "本次响应数据行数，data 集合大小")
    @Override
    public long getRowCount() {
        return super.getRowCount();
    }

    @ApiModelProperty(position = 4, value = "总页数，该参数分页查询时才会起作用，其他情况一直返回 0")
    @Override
    public int getPageCount() {
        return super.getPageCount();
    }

    @ApiModelProperty(position = 5, value = "总行数，该参数分页查询时才会起作用，其他情况一直返回 0")
    @Override
    public long getTotalCount() {
        return super.getTotalCount();
    }

    @ApiModelProperty(position = 7, value = "异常消息，用于开发调试")
    @Override
    public String getException() {
        return super.getException();
    }

    @ApiModelProperty(position = 8, value = "数据集合，查询单条数据或多条数据，都放在泛型集合中")
    @Override
    public List<E> getData() {
        return super.getData();
    }

    @ApiModelProperty(position = 9, value = "扩展属性， 补充 data 集合")
    @Override
    public Map<String, Object> getExtras() {
        return super.getExtras();
    }

    /**
     * 本次链路追踪
     *
     * @return {@link String}
     */
    @ApiModelProperty(position = 6, value = "链路追踪 id")
    public String getXid() {
        return MDC.get("traceId");
    }

    /**
     * 将编码转换成具体消息
     *
     * @return String
     */
    @Override
    public String getMessage() {
        final String message = super.getMessage();
        return StringUtils.isBlank(message) ? this.message : message;
    }

    public void setCode(final String code) {
        this.code = code;
        final Supplier<String> getMessage = () -> this.message;
        super.setCode(new ICode() {
            @Override
            public String name() {
                return code;
            }

            @Override
            public String getComment() {
                return getMessage.get();
            }
        });
    }

    @Override
    public Result<E> setCode(final ICode code) {
        this.code = code.name();
        this.message = code.getComment();
        super.setCode(code);
        return this; // 保证链式请求，返回:this
    }

    @Override
    public Result<E> setException(final String exception) {
        super.setException(exception);
        return this; // 保证链式请求，返回:this
    }
//
//    /**
//     * 设置异常编码及异常信息
//     *
//     * @param code      {@link ICode} 异常响应码
//     * @param exception String 异常消息内容
//     */
//    @Override
//    public Result<E> setException(final ICode code, final String exception) {
//        super.setException(code, exception);
//        return this; // 保证链式请求，返回:this
//    }

    /**
     * 将业务逻辑中捕获到的异常转换为对应的code
     *
     * @param e {@link Exception} 捕获到的异常
     * @return Result<E>
     */
    @Override
    public Result<E> setException(final Exception e) {
        super.setException(e);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 重载方法，设置成功后的数据集合；返回当前对象，便于链式调用
     *
     * @param data List<E>
     * @return Result<E>
     */
    @Override
    public Result<E> setSuccess(final List<E> data) {
        super.setSuccess(data);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 重载方法，设置成功后的数据集合；返回当前对象，便于链式调用
     *
     * @param data E[]
     * @return Result<E>
     */
    @Override
    public Result<E> setSuccess(final E[] data) {
        super.setSuccess(data);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 重载方法，设置成功后的数据集合；返回当前对象，便于链式调用
     *
     * @param data E
     * @return Result<E>
     */
    @Override
    public Result<E> setSuccess(final E data) {
        super.setSuccess(data);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 重载方法，设置成功后的数据集合；返回当前对象，便于链式调用
     *
     * @param page {@link Page <E>}
     * @return Result<E>
     */
    public Result<E> setSuccess(final org.springframework.data.domain.Page<E> page) {
        super.setCode(Code.A00000);
        if (Objects.nonNull(page)) {
            super.setTotalCount(page.getTotalElements());
            super.setPageCount(page.getTotalPages());
            setSuccess(page.getContent());
        }
        return this; // 保证链式请求，返回:this
    }

    /**
     * 重载方法，设置成功后的数据集合；返回当前对象，便于链式调用
     *
     * @param page {@link Page <E>}
     * @return Result<E>
     */
    public Result<E> setSuccess(final QueryResults<E> page) {
        super.setCode(Code.A00000);
        if (Objects.nonNull(page)) {
            super.setTotalCount(page.getTotal());
            super.setPageCount((int) (page.getTotal() / page.getLimit() + (page.getTotal() % page.getLimit() > 0 ? 1 : 0)));
            setSuccess(page.getResults());
        }
        return this; // 保证链式请求，返回:this
    }

    /**
     * 添加扩展属性，返回Result对象本身，支持链式请求
     *
     * @param key   String
     * @param value Object
     * @return Result<E>
     */
    @Override
    public Result<E> addExtras(final String key, final Object value) {
        super.addExtras(key, value);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 添加扩展属性，返回Result对象本身，支持链式请求
     *
     * @return Result<E>
     */
    @Override
    public Result<E> addExtras(final JSONObject obj) {
        super.addExtras(obj);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 添加扩展属性，返回Result对象本身，支持链式请求
     *
     * @return Result<E>
     */
    @Override
    public Result<E> addExtras(final Map<String, String> extras) {
        super.addExtras(extras);
        return this; // 保证链式请求，返回:this
    }

    /**
     * 判断 code 是否为 SUCCESS
     *
     * @return Result<E> code == SUCCESS 返回结果集对象
     * @throws CodeException code != SUCCESS 则抛出异常
     */
    @Override
    @JSONField(serialize = false, deserialize = false)
    public Result<E> isSuccess() throws CodeException {
        super.isSuccess();
        return this;
    }

    /**
     * 判断 code 是否为 SUCCESS
     *
     * @return Result<E> code == SUCCESS 返回结果集对象
     * @throws CodeException code != SUCCESS 则抛出异常
     */
    @Override
    @JSONField(serialize = false, deserialize = false)
    public Result<E> assertSuccess() throws CodeException {
        super.assertSuccess();
        return this;
    }

    /**
     * 判断 rowCount 是否大于0
     *
     * @return true大于0，false等于0
     */
    @Override
    @JSONField(serialize = false, deserialize = false)
    public boolean isRowCount() {
        return super.isRowCount();
    }

    /**
     * 获取data集合中的第一项;获取前先校验集合长度是否大于0
     *
     * @return E
     */
    @Override
    public Optional<E> dataFirst() {
        return super.dataFirst();
    }

    /**
     * <pre>
     * 执行 consumer 代码逻辑；
     * 处理 consumer 异常，并设置到响应对象中，但不会调用 {@link Result#setCode}({@link Code#A00000})，需要在 consumer 中设置成功状态
     * {@link Result#execute} 可执行多次，上一个 {@link Result#execute} 执行失败，并不会影响下一次 {@link Result#execute} 执行，响应状态以最后一次 {@link Result#execute} 指定的状态
     *
     * @param consumer {@link Consumer<Result>}
     * @return {@link Result}{@link Result<E>}
     */
    public Result<E> execute(final Consumer<Result<E>> consumer) {
        try {
            consumer.accept(this);
        } catch (Exception e) {
//            log.error(e.getMessage(), e);
            throw e;
        }
        return this;
    }

    /**
     * 执行 call 代码逻辑；如果 call 不抛异常，则调用 {@link Result#setCode}({@link Code#A00000})
     *
     * @param call {@link ICall}
     * @return {@link Result}{@link Result<E>}
     */
    public Result<E> call(final ICall call) {
        try {
            call.call();
            setCode(Code.A00000);
        } catch (Exception e) {
//            log.error(e.getMessage(), e);
            throw e;
        }
        return this;
    }

    /**
     * <pre>
     * 同 {@link Result#execute} 类似，但是会先判断 code == Code.A00000，才会执行 consumer
     * 一般 then 应该在 {@link Result#execute} 之后，then 表示上一步执行状态为 SUCCESS , 才会继续执行
     *
     * @param consumer {@link Consumer<Result>}
     * @return {@link Result}{@link Result<E>}
     */
    public Result<E> then(final Consumer<Result<E>> consumer) {
        if (Objects.equals(Code.A00000.name(), this.getCode())) {
            try {
                consumer.accept(this);
            } catch (Exception e) {
//                log.error(e.getMessage(), e);
                throw e;
            }
        }
        return this;
    }
    // 扩展方法：end *************************************************************************************************************************************************

    @SuppressWarnings("unchecked")
    @SneakyThrows
    public Result<E> cloneObject() {
        return (Result<E>) super.clone();
    }

    //    public static void main(String[] args) {
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 打印所有状态码 <<<<<<<<<<<<<<<<<<");
//            for (AppCode code : AppCode.values()) {
//                log.info(code + ":" + code.comment);
//            }
//        }
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 打印对象 toJson 之后的全部字段 <<<<<<<<<<<<<<<<<<");
//            log.info(JSON.toJSONString(new Result<>(),
//                    SerializerFeature.WriteMapNullValue,
//                    SerializerFeature.WriteNullBooleanAsFalse,
//                    SerializerFeature.WriteNullListAsEmpty,
//                    SerializerFeature.WriteNullNumberAsZero,
//                    SerializerFeature.WriteNullStringAsEmpty
//            ));
//        }
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 声明data集合中只能是String <<<<<<<<<<<<<<<<<<");
//            Result<String> result = new Result<>();
//            // 设置单一对象，必须是泛型声明的类型
//            result.setSuccess("111");
//            log.info(result.json());
//            // 设置多个对象，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList("222", "333"));
//            log.info(result.json());
//            // 设置对象对象数组，必须是泛型声明的类型
//            result.setSuccess(new String[]{"444", "555"});
//            log.info(result.json());
//            // 设置对象集合，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList("666", "777"));
//            // 带有附加属性(扩展属性),可以链式调用
//            result.addExtras("name", "JX").addExtras("amount", 100).addExtras("roles", new String[]{"ROLE_USER"});
//            log.info(result.json());
//        }
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 声明data集合中只能是Map<String, Object> <<<<<<<<<<<<<<<<<<");
//            Result<Map<String, Object>> result = new Result<>();
//            // 设置单一对象，必须是泛型声明的类型
//            result.setSuccess(Maps.bySO("key", "111"));
//            log.info(result.json());
//            // 设置多个对象，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList(Maps.bySO("key", "222"), Maps.bySO("key", "333")));
//            log.info(result.json());
//            // 设置对象集合，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList(Maps.bySO("key", "444"), Maps.bySO("key", "555")));
//            // 带有附加属性(扩展属性),可以链式调用
//            result.addExtras("name", "JX").addExtras("amount", 100).addExtras("roles", new String[]{"ROLE_USER"});
//                log.info(result.json());
//        }
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 声明data集合中只能是 Item <<<<<<<<<<<<<<<<<<");
//            Result<Item> result = new Result<>();
//            // 设置单一对象，必须是泛型声明的类型
//            result.setSuccess(Item.builder().key("key").value(111).build());
//            log.info(result.json());
//            // 设置多个对象，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList(Item.builder().key("key").value(222).build(), Item.builder().key("key").value(333).build()));
//            log.info(result.json());
//            // 设置对象对象数组，必须是泛型声明的类型
//            result.setSuccess(new Item[]{Item.builder().key("key").value(444).build(), Item.builder().key("key").value(555).build()});
//            log.info(result.json());
//            // 设置对象集合，必须是泛型声明的类型
//            result.setSuccess(Arrays.asList(Item.builder().key("key").value(666).build(), Item.builder().key("key").value(777).build()));
//            // 带有附加属性(扩展属性),可以链式调用
//            result.addExtras("name", "JX").addExtras("amount", 100).addExtras("roles", new String[]{"ROLE_USER"});
//            log.info(result.json());
//            }
//        {
//            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 将 JSON 字符串反序列化为Result对象 <<<<<<<<<<<<<<<<<<");
//            log.info(Result.valueOfJson("{\"code\":\"SUCCESS\",\"message\":\"成功\",\"rowCount\":90,\"pageCount\":100,\"totalCount\":200,\"data\":[\"A\",\"B\"]}").json());
//            log.info(Result.valueOfJson("{\"code\":\"SUCCESS\",\"message\":\"成功\",\"rowCount\":90,\"pageCount\":100,\"totalCount\":200,\"data\":[\"A\",\"B\"]}").json());
//            log.info(Result.valueOfJson("{\"code\":\"FAILURE\",\"message\":\"失败\",\"data\":[{\"name\":\"A\"},{\"name\":\"B\"}]}").json());
//        }
////        {
////            try {
////                Result<Table> result = JSON.parseObject(FileUtil.read("D:\\project\\files\\upload-com-data\\c9d6ad96-3eed-4d70-879b-bead504f0730\\2018\\BudgetMainIncome\\66f871de-5265-462d-8f55-1e34baa0e286.json"), new TypeReference<Result<Table>>(){});
////                log.info("{}",result.dataFirst());
////                log.info(result.json());
////            } catch (IOException e) {
////                log.error(e.getMessage(), e);
////            }
////        }
//
//    }
}
